// https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=APPID&secret=APPSECRET

package wxwoa

import (
	"crypto/sha1"
	"encoding/json"
	"fmt"
	"io"
	"io/ioutil"
	"log"
	"math/rand"
	"net/http"
	"time"

	"gitee.com/chenrh/finego/backends/utils"
	"github.com/kataras/iris/v12"
)

// WxJsapiTicket s
type WxJsapiTicket struct {
	// https://developers.weixin.qq.com/doc/offiaccount/OA_Web_Apps/JS-SDK.html
}

// getTicket
func (c WxJsapiTicket) getTicket(ctx iris.Context) string {
	// 1. 先从缓存里找，如果没有再去请求接口
	_ticket := utils.GetCache(WX_CACHEKEY_JSAPI_TICKET)
	if _ticket != nil {
		return _ticket.(string)
	}

	access_token := WxAccessToken{}.AccessToken(ctx)
	if len(access_token) == 0 {
		ctx.Application().Logger().Warnf("JsApiTicket 在使用 AccessToken 时得到空 AccessToken")
		return ""
	}

	url := fmt.Sprintf("https://api.weixin.qq.com/cgi-bin/ticket/getticket?access_token=%s&type=jsapi", access_token)
	resp, err := http.Get(url)
	if err != nil {
		log.Println("JsApiTicket 请求微信官方接口 ticket/getticket 时出错：", err.Error())
		return ""
	}
	defer resp.Body.Close()

	body, _ := ioutil.ReadAll(resp.Body)
	content := string(body)
	log.Println("-- 获取 ", WX_CACHEKEY_JSAPI_TICKET, " 接口返回：", content)

	var jsonmap map[string]interface{}
	json.Unmarshal([]byte(content), &jsonmap)

	if errmsg, ok := jsonmap["errmsg"]; ok {
		if errmsg == nil {
			return ""
		}
		/*
			{
			"errcode":0,
			"errmsg":"ok",
			"ticket":"bxLdikRXVbTPdHSM05e5u5sUoXNKd8-41ZO3MhKoyN5OfkWITDGgnr2fwJ0m9E8NYzWKVZvdVtaUgWvsdshFKA",
			"expires_in":7200
			}
		*/
		if errmsg.(string) == "ok" {
			ticket := jsonmap["ticket"].(string)
			expires_in := jsonmap["expires_in"].(float64)
			expire := time.Duration(expires_in) * time.Second
			utils.SetCache(WX_CACHEKEY_JSAPI_TICKET, ticket, expire)
			return ticket
		}
		return ""
	}

	ctx.Application().Logger().Warnf("-- 获取 " + WX_CACHEKEY_JSAPI_TICKET + " 接口返回：" + content)
	return ""
}

func (c WxJsapiTicket) createNoncestr(l int) string {
	str := "0123456789abcdefghijklmnopqrstuvwxyz"
	bytes := []byte(str)
	result := []byte{}
	r := rand.New(rand.NewSource(time.Now().UnixNano()))
	for i := 0; i < l; i++ {
		result = append(result, bytes[r.Intn(len(bytes))])
	}
	return string(result)
}

func (c WxJsapiTicket) Signature(ctx iris.Context, url string) WxConfig {
	/*
		签名算法
		签名生成规则如下：参与签名的字段包括noncestr（随机字符串）, 有效的jsapi_ticket, timestamp（时间戳）,
		url（当前网页的URL，不包含#及其后面部分） 。对所有待签名参数按照字段名的ASCII 码从小到大排序（字典序）后，
		使用URL键值对的格式（即key1=value1&key2=value2…）拼接成字符串string1。
		这里需要注意的是所有参数名均为小写字符。
		对string1作sha1加密，字段名和字段值都采用原始值，不进行URL 转义。
		即signature=sha1(string1)。
	*/

	noncestr := c.createNoncestr(8)
	timestamp := fmt.Sprintf("%d", time.Now().UnixNano())

	string1 := "jsapi_ticket=" + c.getTicket(ctx)
	string1 += "&noncestr=" + noncestr
	string1 += "&timestamp=" + timestamp
	string1 += "&url=" + url

	t := sha1.New()
	io.WriteString(t, string1)
	signature := fmt.Sprintf("%x", t.Sum(nil))

	model := WxConfig{
		AppID:     WeChatSubscriptionAppID(ctx),
		Timestamp: timestamp,
		NonceStr:  noncestr,
		Signature: signature,
	}

	return model
}
